// Copyright 2007-2010 Comdiv (F. Sadykov) - http://code.google.com/u/fagim.sadykov/
// Supported by Media Technology LTD 
//  
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//  
//      http://www.apache.org/licenses/LICENSE-2.0
//  
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// 
// MODIFICATIONS HAVE BEEN MADE TO THIS FILE
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Xml.Linq;
using System.Xml.XPath;
using Comdiv.Design;
using Comdiv.Extensions;

namespace Comdiv.Doc{
    public class  TypeDescriptor{
        public Type Type { get; set; }
        public XElement Documentation { get; set; }
        public string DocumentPage { get; set; }

        public IList<Type> Descendants{
            get { return descendants; }
        }

        private IDictionary<string, string> _designAttributes;

        private IList<Type> descendants =new List<Type>();
        public string Name{
            get { return this.Type.Name; }
        }
        public string FullName
        {
            get { return this.Type.FullName; }
        }
        public string Assembly
        {
            get { return this.Type.Assembly.GetName().Name; }
        }
        public string Namespace
        {
            get { return this.Type.Namespace; }
        }

        public IList<PropertyInfo> GetProperties(){
            return GetProperties(false);
        }

        public IList<MethodInfo> GetMethods(){
            return GetMethods(false).Where(x => !isPropertyAccessor(x)).ToList();
        }

        private bool isPropertyAccessor(MethodInfo x){
            Console.WriteLine(x.Name);
            return (x.Name.StartsWith("get_") || x.Name.StartsWith("set_") || x.Name.StartsWith("add_") || x.Name.StartsWith("remove_"));
        }

        public IList<MethodInfo> GetMethods(bool useProtected)
        {
            if (!useProtected) return Type.GetMethods();
            return Type.GetMethods(BindingFlags.NonPublic).Where(x => isProtected(x) && !isPropertyAccessor(x)).ToList();
        }

        public IList<PropertyInfo> GetProperties(bool useProtected)
        {
            if (!useProtected) return Type.GetProperties();
            return Type.GetProperties(BindingFlags.NonPublic).Where(x => isProtected(x) ).Where(x=>!x.IsSpecialName).ToList();
        }

        public IList<Type> GetInterfaces(){
            return Type.GetInterfaces().OrderBy(t => t.FullName).ToList();
        }

        public Type BaseType { get { return Type.BaseType; } }

        bool isProtected(PropertyInfo info){
            if(info.CanRead){
                if((info.GetGetMethod().Attributes&(MethodAttributes.Family|MethodAttributes.FamORAssem))!=0){
                    return true;
                }
                return false;
            }
            return false;
        }

        bool isProtected(MethodInfo info)
        {
            
            return (info.Attributes & (MethodAttributes.Family | MethodAttributes.FamORAssem)) != 0;
        }

       public IList<FieldInfo> GetFields(){
           return this.Type.GetFields();
       }

        public string Summary{
            get{
                var summary = this.Documentation.XPathSelectElement("//type/summary");
                if (null == summary||summary.Value.noContent()) return "*NO SUMMARY PROVIDED*";
                return summary.Value;
            }
        }


        public IDictionary<string, string> DesignAttributes{
            get{
                if(null==_designAttributes){
                    _designAttributes = new Dictionary<string, string>();
                    foreach (BaseDesignAttribute dattr in this.Type.GetCustomAttributes(typeof(BaseDesignAttribute),true)){
                        _designAttributes[dattr.GetType().Name.Replace("Attribute", "")] = dattr.Message;
                    }
                }
                return _designAttributes;
            }
        }

        public XElement GetDoc(MethodInfo info){
            return Documentation.XPathSelectElement("//member[@name='" + ToHelpString(info) + "']");
        }

        public static string ToHelpString(MethodInfo info)
        {
            return info.Name + getGens(info)+ "(" + info.GetParameters().Select(x => resolveParamTypeName(x)).concat(",") + ")";
        }

        private static string getGens(MethodInfo info){
            var genargs = info.GetGenericArguments();
            if (genargs.Length == 0) return "";
            return "``" + genargs.Length;
        }

        private static string resolveParamTypeName(ParameterInfo x){
            var mi = (MethodInfo) x.Member;
            var t = mi.DeclaringType;
            if (x.ParameterType.FullName != null){
                return x.ParameterType.FullName;
            }
            var genname = x.ParameterType.Name;
            var idx = 0;
            foreach(var arg in mi.GetGenericArguments()){
                if(arg.Name==genname) return "``" + idx;
                idx++;
            }
            return "WRONG";
        }

        public static string ToHelpString(PropertyInfo info)
        {
            return info.Name;
        }
    }
}